/*
--------------------------------------------------------------------------------
				Ak-Lib. 
			 Project       	: Ak-Lib
			 Group         	: Ak-Lib R&D Team
			 Author        	: Ocean.Wang
			 Create Date 	: 05-01-2010
--------------------------------------------------------------------------------
Code Name 	:  A.K 	~v~
Description	:  Yet Another Cross-Platform Lib.
Cautions    	:
--------------------------------------------------------------------------------
Change History:
Version		: 0.1
Building 		: 05/01/10
10-05.01 first draft, build, debug and test.
--------------------------------------------------------------------------------
*/

#include "ak_cli.h"
#include "ak_socket.h"
#include "ak_devl.h"
#include <unistd.h>

static 	int 	_gTraceLvl_DevL = TRACELVL_WARNING;

static char * 	_gCmdNExist_DevAgt =	"command not found";

#define _SAGT_DEV_APPLET_HASH 		2
#define _SAGT_DEV_APPLET_MAX 		16		/* Each Device's Application Process Max Count */

#define _SAGT_DEV_RELAY_TO 			10000
#define _SAGT_DEV_SHM_NAME 			"/var/femto/fcast_shm"
#define _SAGT_DEV_TASK_STACK 		0X100000
#define _SAGT_DEV_TASK_PRI 			90


/* -----------------------------------------------------------------------
** 	Device Level's OAM info 
**	Each Device will have a Daemon to Moniter the APP/MOD/SAP status.
** 	The Daemon will Relay the CLI Interface.
**	The Application's Load is done by the OS's Enviorment Setup/Config/Init Script.
**	the Daemon will moniter the all the Application's Runtime OOS/INS.
**	
** 	Althrough a Device may have several ENET Interface & Multi-IP, only 1 IP is used in the OAM VLAN.
** 	The Cast Port is based on that IP.
**/
typedef struct _t_devApplet{
	_t_bnode 			appNode;
	_t_bnode 			hashNode;
	char 				appName[S_APP_MAX_NAME+1];

	/* Cli USock Info */
	S_SOCKET_ADDRUX 	addrCtrl;
}_t_devApplet;

static 	void 	_SDevL_Applet_Init(_t_devApplet * pApp)
{
	SYS_MEMZERO(pApp, sizeof(_t_devApplet));
	return;
}

typedef struct _t_devAgt{
	/* Process Info */
	int 			bInit;
	
	_t_sysCS 		devLock;

	/* Task */
	_t_sysTask		taskCli;
	_t_sysTask 		taskCtrl;
	_t_sysTask		taskRelay;
	_t_sysTask 		taskCast;

	/* Command Info */
	_t_cliCmdTbl 	cmdTbl;

	/* Socket */
	int 				sockCtrl;
	int 				sockCli;
	int 				sockRelay;
	int 				sockCast;

	S_SOCKET_ADDRUX 	addrCtrl;
	S_SOCKET_ADDRUX 	addrCli;
	S_SOCKET_ADDRIN 	addrCast;
	S_SOCKET_ADDRIN 	addrRelay;
	
	/* Device Info & ENet Info, FFT */

	/* App Active Queue */
	_t_blist 				appQue;
	_t_blist 				hashQue[_SAGT_DEV_APPLET_HASH];

	/* App Pool */
	_t_blist 				appPool;
	_t_devApplet 			applet[_SAGT_DEV_APPLET_MAX]; 			

	
}_t_devAgt;

static 	_t_devAgt 	_gAgt_Dev;

/* -----------------------------------------------------------------------
** 	Device Agent Signal Handler.
*/
static 	int 	_gSigCnt_Dev = 0;
static 	int 	_gSigTbl_Dev[]={
	SIGBUS,
	SIGFPE,

	#if 0
	SIGHUP,
	#endif
	
	SIGILL,
	SIGINT,
	SIGIOT,
	SIGQUIT,
	SIGSEGV,
	SIGTERM,
	SIGTRAP,
	SIGUSR1,
	SIGUSR2
};

static 	void 	_SDevL_Dev_SigHandler(int signo)
{
	if(_gSigCnt_Dev++){
		/* Avoid Double Fault */
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Dev Signal %d During Cleanup. Exit!\n", signo);
		exit(1);
	}
	
	/* Check AppAgt Init */
	if(_gAgt_Dev.bInit == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		exit(2);
	}	

	/* Terminate */
	SYS_CLOSE(close, 	_gAgt_Dev.sockCtrl);
	SYS_CLOSE(close, 	_gAgt_Dev.sockCli);
	SYS_CLOSE(close, 	_gAgt_Dev.sockRelay);
	SYS_CLOSE(close, 	_gAgt_Dev.sockCast);
	
	exit(0);
}


/* -----------------------------------------------------------------------
**	Command Table Of DevAgent
**
*/
static 	int 	_SAgtDev_RegCmd(_t_devAgt * pDevAgt, _t_cliCmdReg * pCmdReg)
{
	_t_cliCommand 	* pCommand;
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	char 			* pCmdStr;
	int 			  i, len, ret, hashKey;
	
	/* Check Cmd */
	pCmdStr = pCmdReg->cmd;
	if(pCmdStr[0] == '\0'){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command: Error.\n");
		return -1;		
	}
	if(	SStrJ_Avail(pCmdStr)== -1 ){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command:[%s] Illegal.\n", pCmdStr);
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pDevAgt->cmdTbl.hashQue[hashKey]);

	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command:[%s] Dup.\n", pCmdStr);
			return -1;
		}
	}

	/* Alloc the Cmd Struct */
	pCommand = SYS_MALLOC(sizeof(_t_cliCommand));
	if(!pCommand){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command:[%s] Alloc Fail.\n", pCmdStr);
		return -1;
	}
	SYS_MEMCPY(&(pCommand->cmdReg), pCmdReg, sizeof(_t_cliCmdReg));

	/* Add 2 Que */
	pQue 	= &(pDevAgt->cmdTbl.cmdQue);
	BLST_ADD2T(pQue, &(pCommand->cmdNode));
	pQue 	= &(pDevAgt->cmdTbl.hashQue[hashKey]);
	BLST_ADD2T(pQue, &(pCommand->hashNode));
	return 0;
	
}

extern	int 	SAgtDev_RegCmd(void * pDevice, _t_cliCmdReg * pCmdReg);
int 	SAgtDev_RegCmd(void * pDevice, _t_cliCmdReg * pCmdReg)
{
	_t_devAgt * 	pDevAgt;
	int 				ret;
	
	if(!pDevice || !(pCmdReg) || !(pCmdReg->func.cbProc)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command Register Error.\n");
		return -1;
	}
	
	pDevAgt = (_t_devAgt *)pDevice;
	SYS_ENTER_CS(&(pDevAgt->devLock));
	ret = _SAgtDev_RegCmd(pDevAgt, pCmdReg);
	SYS_LEAVE_CS(&(pDevAgt->devLock));

	return ret;
}

static 	int 	_SAgtDev_ShowStat(void * pArg, int lArg, void * pDevice, char * outBuf, int outLen)
{
	_t_devAgt * pDevAgt;
	_t_devApplet * pApplet;
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	
	int i, len, count;

	if(!pDevice || !(outBuf) || (outLen <= 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Device Command Error.\n");
		return -1;
	}
	pDevAgt = (_t_devAgt *)pDevice;
	len = 0;

	pQue = &(pDevAgt->appQue);
	count= pQue->count;
	for(i=0, pNode=pQue->next; 	i<count; 	i++, pNode=pNode->next){
		pApplet = _O_PARENT(_t_devApplet, appNode, pNode);
		len += SYS_SNPRINTF(outBuf+len, outLen - len, "[Applet %02d]:[%s]\n",
			i, pApplet->appName);
		if(len >= outLen)
			break;
	}

	return len;
}

static 	_t_cliCmdReg 	_gCmd_AgtDev[]={
		{"showstat", {(int (*)())_SAgtDev_ShowStat, NULL, 0}}
};


/* -----------------------------------------------------------------------
** 	Device CLI. Relay. Cast. 
** 	The Dev Agent CLI Stub. 
**	Check the Route Info in the Message to judge if Need Relay to Other Dev Agent.
**	Dispatch the Message to Applet.
*/
static 	int 	_SAgtDev_SockInit(_t_devAgt * pDevAgent)
{
	int 	ret;

	ret = 0;
	/* 
	**	Ctrl Socket 
	*/
	if(SAgtSock_InitUnix(&(pDevAgent->sockCtrl), &(pDevAgent->addrCtrl), "root.ctrl") == 0){
		/* 
		**	Cli Socket 
		*/
		if(SAgtSock_InitUnix(&(pDevAgent->sockCli), &(pDevAgent->addrCli), "root.cli") == 0){
			/* 
			**	Relay Socket 
			*/
			if(SAgtSock_InitUdp(&(pDevAgent->sockRelay), &(pDevAgent->addrRelay), _S_CLI_PORT_SVR) == 0){
				/* 
				**	Cast Socket 
				*/
				if(SAgtSock_InitUdp(&(pDevAgent->sockCast), &(pDevAgent->addrCast), _SCAST_PORT) == 0){
					S_SOCK_SET_BROADCAST(pDevAgent->sockCast, ret);
					return 0;
				}else{
					SYS_CLOSE(close, pDevAgent->sockCtrl);
					SYS_CLOSE(close, pDevAgent->sockCli);
					SYS_CLOSE(close, pDevAgent->sockRelay);
				}
			}else{
				SYS_CLOSE(close, pDevAgent->sockCtrl);
				SYS_CLOSE(close, pDevAgent->sockCli);
			}
		}else{
			SYS_CLOSE(close, pDevAgent->sockCtrl);
		}
	}
	
	return -1;
}


/* -----------------------------------------------------------------------
** 	Device Agent Init.
*/
static	void * 	_SAgtDev_Cli(_t_devAgt * pDevAgt);
static 	void * 	_SAgtDev_Ctrl(_t_devAgt * pDevAgt);
static 	void * 	_SAgtDev_Relay(_t_devAgt * pDevAgt);

static 	int 	_SAgtDev_Init(_t_devAgt* pDevAgt)
{
	
	int 			i, len;
	_t_blist * 	pQue;
	_t_devApplet*pApp;

	if(Sys_ChkInst(_SAGT_DEV_SHM_NAME) != 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Already Running.\n");
		return -1;
	}

	if(pDevAgt->bInit != 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Init Already.\n");
		return -1;
	}
	
	/* Cli/Relay/Cast Socket Info */
	if(_SAgtDev_SockInit(pDevAgt) == -1){
		return -1;
	}

	/* Command Table */
	pQue  = &(pDevAgt->cmdTbl.cmdQue);
	BLIST_INIT(pQue);	
	for(i=0, pQue=pDevAgt->cmdTbl.hashQue; 
		i<_S_CLI_CMD_HASH; 	i++, pQue++){
		BLIST_INIT(pQue);	
	}

	/* Init the Agt Info */
	SYS_INIT_CS(&(pDevAgt->devLock));
	BLIST_INIT(&(pDevAgt->appQue));	
	for(i=0; i<_SAGT_DEV_APPLET_HASH; i++){
		BLIST_INIT(&(pDevAgt->hashQue[i]));	
	}
	
	pQue=&(pDevAgt->appPool);
	BLIST_INIT(pQue);
	for(i=0, pApp=pDevAgt->applet; 
		i<_SAGT_DEV_APPLET_MAX; 	i++, pApp++){

		_SDevL_Applet_Init(pApp);
		BLST_ADD2T(pQue, &(pApp->appNode));
	}

	/* Init the Command */
	len = _N_ARRAY(_gCmd_AgtDev);
	for(i=0; i<len; i++){
		SAgtDev_RegCmd(pDevAgt, &(_gCmd_AgtDev[i]));
	}

	/* Signal Exception Handler */
	if(signal(SIGPIPE, SIG_IGN) == SIG_ERR){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Dev SigHandler %d Fail.\n", SIGPIPE);
		return -1;
	}

	len = _N_ARRAY(_gSigTbl_Dev);
	for(i=0; i<len; i++){
		if(signal(_gSigTbl_Dev[i], _SDevL_Dev_SigHandler) == SIG_ERR){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Dev SigHandler %d Fail.\n", _gSigTbl_Dev[i]);
			return -1;
		}
	}
	
	pDevAgt->bInit = 1;

	/* Step 1: Let's Spawn MsgQ Control */
	STASK_CRATE((pDevAgt->taskCtrl),
				_SAGT_DEV_TASK_STACK, 
				_SAGT_DEV_TASK_PRI,
				_SAgtDev_Ctrl, 
				 pDevAgt);

	/* Step 2: Let's Spawn CLI - APP  */
	STASK_CRATE((pDevAgt->taskCli), 
				_SAGT_DEV_TASK_STACK, 
				_SAGT_DEV_TASK_PRI,	
				_SAgtDev_Cli, 
				 pDevAgt);

	/* Step 3: Let's Spawn CLI -Relay */
	STASK_CRATE((pDevAgt->taskRelay), 
				_SAGT_DEV_TASK_STACK, 
				_SAGT_DEV_TASK_PRI,	
				_SAgtDev_Relay, 
				 pDevAgt);
	

	/* Step 4: Let's Spawn Cast Rx */
	
	/* Step 5: Let's Cast Tx */


	return 0;
}
	
static 	int 	_SAgtDev_AppletAdd(_t_devAgt* pDevAgt, char * appName)
{
	_t_devApplet * 	pApp;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	int 				i, len, ret, hashKey;

	/* Check DevAgt Init */
	if(!pDevAgt || (pDevAgt->bInit == 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return -1;
	}	

	if(!appName || (appName[0] == 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Name Error.\n");
		return -1;
	}
	
	len = strlen(appName);
	if(len >= S_APP_MAX_NAME)
		len = S_APP_MAX_NAME;
	
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(appName[i]);
	}
	/* Hash ModId to Check if Already Reg */
	hashKey = ret%_SAGT_DEV_APPLET_HASH;
	pQue = &(pDevAgt->hashQue[hashKey]);

	ret = 0;
	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pApp = _O_PARENT(_t_devApplet, hashNode, pNode);
		if(strcmp(pApp->appName, appName) == 0){
			ret = -1;
			break;
		}
	}

	if(ret == -1){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Dup:[%s].\n", pApp->appName);
		return -1;
	}
	
	/* Alloc a Applet */
	pQue = &(pDevAgt->appPool);
	pApp = (_t_devApplet *)BLST_GET(pQue);

	if(pApp == NULL){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Alloc Fail.\n");
		return -1;
	}
	strncpy(pApp->appName, appName, len);
	pApp->appName[len]	= '\0';
	
	/* Cli Socket */
	pApp->addrCtrl.sun_family = AF_UNIX;
	i = SYS_SNPRINTF(pApp->addrCtrl.sun_path, 	_SCAST_USOCK_NAME-1, 
					_SCAST_USOCK_PREFIX, pApp->appName); /* Here we byPass the delimeter */
	pApp->addrCtrl.sun_path[i] = '\0'; 
	

	/* Add to Que & Hash */
	BLST_ADD2T(&(pDevAgt->appQue), &(pApp->appNode));
	pQue = &(pDevAgt->hashQue[hashKey]);
	BLST_ADD2T(pQue, &(pApp->hashNode));
	
	SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Register:[%s].\n", pApp->appName);
	return 0;
}

static 	_t_devApplet * 	_SAgtDev_AppletGet(_t_devAgt* pDevAgt, char * appName)
{
	_t_devApplet * 	pApp;
	_t_devApplet * 	pRet;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	int 				i, len, ret, hashKey;

	/* Check DevAgt Init */
	if(!pDevAgt || (pDevAgt->bInit == 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return NULL;
	}	

	if(!appName){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Name Error.\n");
		return NULL;
	}
	
	len = strlen(appName);
	if(len >= S_APP_MAX_NAME)
		len = S_APP_MAX_NAME;
	
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(appName[i]);
	}
	/* Hash ModId to Check if Already Reg */
	hashKey = ret%_SAGT_DEV_APPLET_HASH;
	pQue = &(pDevAgt->hashQue[hashKey]);

	pRet = NULL;
	for(i=0, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pApp = _O_PARENT(_t_devApplet, hashNode, pNode);
		if(strcmp(pApp->appName, appName) == 0){
			pRet = pApp;
		}
	}
	
	return pRet;
}


static 	int 	_SAgtDev_AppletDel(_t_devAgt* pDevAgt, char * appName)
{
	_t_devApplet * 	pApp;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	_t_bnode	    * 	pNext;
	int 				i, len, ret, hashKey;

	/* Check DevAgt Init */
	if(!pDevAgt || (pDevAgt->bInit == 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return -1;
	}	

	if(!appName){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet Name Error.\n");
		return -1;
	}
	
	len = strlen(appName);
	if(len >= S_APP_MAX_NAME)
		len = S_APP_MAX_NAME;
	
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(appName[i]);
	}
	/* Hash ModId to Check if Already Reg */
	hashKey = ret%_SAGT_DEV_APPLET_HASH;
	pQue = &(pDevAgt->hashQue[hashKey]);

	ret = -1;
	for(i=0, pNext=pQue->next; 
		i<pQue->count; 
		i++){
		pNode = pNext;		pNext = pNode->next;

		pApp = _O_PARENT(_t_devApplet, hashNode, pNode);
		if(strcmp(pApp->appName, appName) == 0){
			/* Add to Que & Hash */
			BLST_DEL(&(pDevAgt->appQue), &(pApp->appNode));
			pQue = &(pDevAgt->hashQue[hashKey]);
			BLST_DEL(pQue, &(pApp->hashNode));

			pQue = &(pDevAgt->appPool);
			BLST_ADD2H(pQue, &(pApp->appNode));
			ret = 0;
			break;
		}
	}

	if(ret == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "Applet UnRegister:[%s].\n", pApp->appName);
	}

	return ret;
}


/* -----------------------------------------------------------------------
** 	Device Application Module Fini
** 	Go Through all Modules' Dtor, if not NULL, Call them.
*/
static 	int 	_SAgtDev_Fini(_t_devAgt* pDevAgt)
{
	int 				i, count;
	_t_devApplet * 	pApp;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;
	
	/* Check DevAgt Init */
	if(pDevAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return -1;
	}	

	/* Go Through All Applications. Send Fini Msg */
	pQue 	= &(pDevAgt->appQue);
	count 	= pQue->count;

	SYS_ENTER_CS(&(pDevAgt->devLock));
	SYS_TRACE(_gTraceLvl_DevL, TRACELVL_NORMAL, "DevAgt Total [%d] Applets.\n", count);
	for(i=0, pNode=pQue->next; i<count; i++, pNode=pNode->next){
		pApp = _O_PARENT(_t_devApplet, appNode, pNode);
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_NORMAL, "Fini Applet[%s] .\n", pApp->appName);

	}
	SYS_LEAVE_CS(&(pDevAgt->devLock));

	/* Close the Handle */
	SYS_CLOSE(close, 	pDevAgt->sockCli);
	SYS_CLOSE(close, 	pDevAgt->sockCast);
	
	return 0;
}

/* -----------------------------------------------------------------------
** Control Of DevAgent
**
*/
static 	int 	_SAgtDev_CtrlStub(void 			* 	pArg, int lArg, 
									unsigned char 	* 	pMsg, 	int msgLen, 
									S_SOCKET_ADDRUX *	pSockAddr)
{
	_t_devAgt	  * pDevAgt;
	_t_castMsgHdr * pMsgHdr;
	char 		  * pPos;
	
	pDevAgt = (_t_devAgt *)pArg;
	if(!pDevAgt){
		return -1;
	}

	/* Judge the Msg */
	pMsgHdr = (_t_castMsgHdr *)pMsg;
	if(pMsgHdr->length != msgLen){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_WARNING, "DevAgt MsgRecv Length[%d - %d] Error.\n",
			msgLen, pMsgHdr->length);
		return -1;
	}
	switch(pMsgHdr->type){
		case _SCAST_APP_REG_REQ:
			pPos = (char *)(pMsgHdr->data);
			SYS_ENTER_CS(&(pDevAgt->devLock));
			_SAgtDev_AppletAdd(pDevAgt, pPos);
			SYS_LEAVE_CS(&(pDevAgt->devLock));
			break;

		case _SCAST_APP_UNR_REQ:
			pPos = (char *)(pMsgHdr->data);
			SYS_ENTER_CS(&(pDevAgt->devLock));
			_SAgtDev_AppletDel(pDevAgt, pPos);
			SYS_LEAVE_CS(&(pDevAgt->devLock));
			break;

		default:
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_WARNING, "DevAgt MsgRecv Unknown[T:%d - L:%d].\n",
				pMsgHdr->type, msgLen);
			break;
	}
		
	return 0;
}

static 	void * 	_SAgtDev_Ctrl(_t_devAgt* pDevAgt)
{
	int 					ret;
	_t_cbentry 		cbEntry;
	
	/* Check DevAgt Init */
	if(pDevAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return NULL;
	}

	_CBENTRY_INIT(&(cbEntry), _SAgtDev_CtrlStub, pDevAgt, 0);
	while(1){
		ret = SockRxSel_Unix(pDevAgt->sockCtrl, &cbEntry, _SAGT_DEV_RELAY_TO);
	}
	
	return NULL;
}

/* -----------------------------------------------------------------------
**	CLI Of DevAgent
**
*/
static 	int 	_SAgtDev_Relay_AppletGet(_t_devAgt	* 	pDevAgt, 
													char * pPath, 	int lenPath,
													_t_devApplet ** ppApplet,
													char * pSubPath)
{
	char 			* 	pPos;
	_t_devApplet * 	pApplet;
	char 				appName[S_APP_MAX_NAME + 1];
	int 				lenApp;
	
	if((pPath[0] != '/') || (pPath[lenPath-1] != '/')){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg Path:[%s] Error.\n",
			pPath);
		return -1;
	}

	pApplet = NULL;
	pPos  	= strchr(pPath+1, '/');
	if(pPos != NULL){
		lenApp = pPos - pPath - 1;
		if(lenApp >= S_APP_MAX_NAME){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg App:[%s] Error.\n",
				pPath);
			return -1;
		}
		strncpy(appName, pPath+1, lenApp);
		appName[lenApp]	= '\0';
		/* Now Let's Get the Applet */
		SYS_ENTER_CS(&(pDevAgt->devLock));
		pApplet = _SAgtDev_AppletGet(pDevAgt, appName);
		SYS_LEAVE_CS(&(pDevAgt->devLock));
		
		if(pApplet == NULL){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg App:[%s] Error.\n",
				appName);
			return -1;
		}
		lenApp = strlen(pPos);
		if(lenApp >= S_APP_MAX_PATH){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt SubPath:[%s] Error.\n",
				pPos);
			return -1;
		}
		strncpy(pSubPath, pPos, lenApp);
		pSubPath[lenApp] = '\0';
		*ppApplet = pApplet;	
		return 1;
	}
	else{
		*ppApplet = NULL;
		return 0;
	}
	return -1;
}


static 	int 	_SAgtDev_CmdConn( _t_devAgt	* 	pDevAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* pRspElem;
	int 			len;
	char 			connStr[S_CLI_MAX_PARAM];

	len = SYS_SNPRINTF(	connStr, S_CLI_MAX_PARAM, 
					"Welcome to Relay Agent. Connection Accept.\n");
	
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_CONNECT;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;

	SYS_MEMCPY(pRspElem->reqRsp, connStr, len);
	pRspElem->reqRsp[len]= '\0';
	len += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;
	
	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtDev_CmdError( _t_devAgt	* 	pDevAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* pRspElem;
	int 			len;
	char 			errStr[S_CLI_MAX_PARAM];

	len = SYS_SNPRINTF(	errStr, S_CLI_MAX_PARAM, 
					"Command Error.\n");
	
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_ERROR;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	
	SYS_MEMCPY(pRspElem->reqRsp, errStr, len);
	pRspElem->reqRsp[len]= '\0';
	len += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;

	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtDev_CmdOk( _t_devAgt	* 	pDevAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* pRspElem;
	int 			len;
	char 			okStr[S_CLI_MAX_PARAM];


	
	len = SYS_SNPRINTF(	okStr, S_CLI_MAX_PARAM, 
					"Command Ok.\n");
	
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_OK;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	
	SYS_MEMCPY(pRspElem->reqRsp, okStr, len);
	pRspElem->reqRsp[len]= '\0';
	len += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;

	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtDev_CmdLs( _t_devAgt	* 	pDevAgt,
											char * outBuf, 	int    outLen)
{
	_t_cliElemRsp* 	pRspElem;
	int 				i, count, len;
	_t_devApplet * 	pApp;
	_t_blist 		* 	pQue;
	_t_bnode	    * 	pNode;

	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_LS;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	len 	= 0;
	outLen -= sizeof(_t_sysMsgElem)+2; /* For '\n', '\0' Use */

	/* Let's go through all the Applets */
	pQue 	= &(pDevAgt->appQue);
	count 	= pQue->count;
	#if 0
	SYS_TRACE(_gTraceLvl_DevL, TRACELVL_DEBUG, "DevAgt [%d]Applets.\n", count);
	#endif
	
	for(i=0, pNode=pQue->next; 
		i<count; 
		i++, pNode=pNode->next){
		pApp = _O_PARENT(_t_devApplet, appNode, pNode);

		len += SYS_SNPRINTF(pRspElem->reqRsp+len, outLen-len,  _CLI_FMT_APP, pApp->appName);
		if(len >= outLen){
			break;
		}
	}
	pRspElem->reqRsp[len]= '\n';
	pRspElem->reqRsp[len+1]= '\0';
	len += 2;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;

	return 	(pRspElem->msgElem.length);					
}

static 	int 	_SAgtDev_CmdLCmd( _t_devAgt	* 	pDevAgt,
											char * outBuf, 	int    outLen)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand* pCommand;
	_t_cliElemRsp* pRspElem;
	int 			i, count, total;

	if((!pDevAgt) || (!outBuf)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Error.\n");
		return -1;
	}

	/* Init the pRspElem */
	pRspElem = (_t_cliElemRsp *)outBuf;
	pRspElem->msgElem.type 	= _CLI_CMD_LCMD;
	pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
	pRspElem->msgElem.reserv= 0;
	outLen -= sizeof(_t_sysMsgElem) + 2; /* For '\n', '\0' */
	outBuf 	= pRspElem->reqRsp;
	
	pQue  = &(pDevAgt->cmdTbl.cmdQue);
	count = pQue->count;
	total = 0;

	for(i=0, pNode = pQue->next; i<count; i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, cmdNode, pNode);

		if(strlen(pCommand->cmdReg.cmd) == 0)
			continue;

		total += SYS_SNPRINTF(outBuf+total, outLen - total, _CLI_FMT_APP_COMMAND, pCommand->cmdReg.cmd);

		/* Judge Buffer */
		if(total >= outLen){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt CmdLs Rsp Buffer [%d - %d] Overflow.\n", 
				total, outLen);
			break;
		}
	}
	
	pRspElem->reqRsp[total]  	= '\0';
	total += 1;
	pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + total;
		
	return pRspElem->msgElem.length;
}

static 	int 	_SAgtDev_CmdExec( _t_devAgt	* 	pDevAgt,
									char * outBuf, 	int   outLen,
									char * pCmdStr,
									char * pParam)
{
	_t_bnode 		* pNode;
	_t_blist 		* pQue;
	_t_cliCommand* pCommand;
	_t_cliElemRsp* pRspElem;
	_t_cbentry 	 * pCbEntry;
	int 			i, len, ret, hashKey;
	
	if((!pDevAgt) || (!outBuf) || (!pCmdStr) || (!pParam) || (outLen <= 0)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Error.\n");
		return -1;
	}

	/* Hash Command to Check if Already Reg */
	len = strlen(pCmdStr);
	for(i=0, ret=0; i<len; i++){
		ret += (unsigned char )(pCmdStr[i]);
	}
	hashKey = ret%_S_CLI_CMD_HASH;
	pQue 	= &(pDevAgt->cmdTbl.hashQue[hashKey]);

	for(i=0, ret=-1, pNode=pQue->next; 
		i<pQue->count; 
		i++, pNode=pNode->next){
		pCommand = _O_PARENT(_t_cliCommand, hashNode, pNode);
		if(strcmp(pCommand->cmdReg.cmd, pCmdStr) == 0){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Command:[%s].\n", pCmdStr);
			ret = 0;
			break;
		}
	}
	
	if(ret == -1){
		/* Judge Buffer */
		if((sizeof(_t_sysMsgElem) + strlen(_gCmdNExist_DevAgt)) >= outLen){
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt CmdExec Rsp Buffer Overflow.\n");
			return -1;
		}
		/* Init the pRspElem */
		pRspElem = (_t_cliElemRsp *)outBuf;

		len = strlen(_gCmdNExist_DevAgt);
		pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
		pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
		pRspElem->msgElem.reserv= 0;
		SYS_MEMCPY(pRspElem->reqRsp, _gCmdNExist_DevAgt, len);
		pRspElem->reqRsp[len] = '\0';
		len += 1;
		pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + len;
		ret  	= (sizeof(_t_sysMsgElem) + len);
	}

	else{
		pCbEntry = &(pCommand->cmdReg.func);
		if(pCbEntry->cbProc){
			/* Init the Output Buf for CallBack Entry */
			pRspElem = (_t_cliElemRsp *)outBuf;
			pRspElem->msgElem.type 	= _CLI_CMD_EXEC;
			pRspElem->msgElem.dir 	= _CLI_MSG_ELEM_RSP;
			pRspElem->msgElem.reserv= 0;
			pRspElem->reqRsp[0] = '\0';

			outBuf  += sizeof(_t_sysMsgElem);
			outLen 	-= sizeof(_t_sysMsgElem) + 2;
			ret = pCbEntry->cbProc(	pCbEntry->pArg,
									pCbEntry->lArg,
									pDevAgt,
									outBuf,
									outLen,
									pParam);
			if( (ret >= 0) && (ret < outLen)){
				pRspElem->reqRsp[ret]='\0';
				ret += 1;
				pRspElem->msgElem.length= sizeof(_t_sysMsgElem) + ret;
				ret += sizeof(_t_sysMsgElem);
			}
			else{
				SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt CmdExec Rsp Buffer [%d - %d] Overflow.\n", 
					ret, outLen);
				ret = -1;
			}
		}
	}
	
	return ret;
}

#define _SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret) 	\
	do{\
		if(ret > 0){\
			(pCmdHdr)->length = ret + sizeof(_t_cliCmdHdr);\
			ret = SockTx_Udp((pDevAgt)->sockRelay, outBuf, (pCmdHdr)->length, pSockAddr);\
		}else{\
			return -1;\
		}\
	}while(0)

#define _SAGTDEV_CMD_ROUTE(pDevAgt, pApplet, pRouteCmd, pRouteElem, pCmdHdr, pReqElem, ipAddr, port, subPath, lenPath, outBuf, ret) 	\
	do{\
		/* We Just Route It .... */\
		pRouteCmd 	= (_t_cliCmdReq*)outBuf;\
		pCmdHdr 	= &((pRouteCmd)->cmdHdr);	CLI_CMDHDR_INIT(pCmdHdr, ipAddr, port);\
		pRouteElem 	= (pRouteCmd)->reqElem;		SYS_MEMCPY(pRouteElem, pReqElem, sizeof(_t_cliElemReq));\
		lenPath = strlen(subPath);				SYS_MEMCPY((pRouteElem)->path, subPath, lenPath);\
		(pRouteElem)->path[lenPath] = '\0';\
		(pCmdHdr)->length = sizeof(_t_cliElemReq) + sizeof(_t_cliCmdHdr);\
		ret = SockTx_Unix((pDevAgt)->sockCli, outBuf, (pCmdHdr)->length, &((pApplet)->addrCtrl));\
	}while(0)

static  int 	_SAgtDev_RelayProc(_t_devAgt 	  * pDevAgt, 
									_t_cliElemReq *	pReqElem,
									unsigned char * outBuf, 
									unsigned int 	ipAddr, 
									unsigned short 	port,
									S_SOCKET_ADDRIN*pSockAddr)
{
	int 	ret, bHasSub;
	int		lenPath, lenParam, lenCmd;
	
	/* Route */
	_t_cliCmdReq 	*	pRouteCmd;
	_t_cliElemReq	*	pRouteElem;

	/* Command Response */
	_t_sysMsgElem 	* 	pMsgElemReq;
	_t_cliCmdRsp 	* 	pRspCmd;
	_t_cliElemRsp	* 	pRspElem;

	/* Msg Header & Element */
	_t_cliCmdHdr 	*	pCmdHdr;

	/* Sub Path */
	char 			* 	pPath;
	char 			 	subPath[S_APP_MAX_PATH + 1];

	/* Applet */
	_t_devApplet * 	pApplet;

	pMsgElemReq = (_t_sysMsgElem *)(&pReqElem->msgElem);
	/* Check Msg Elem */
	if(pMsgElemReq->dir != _CLI_MSG_ELEM_REQ){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg Dir Error.\n");
		return -1;
	}
	lenCmd 		= strlen(pReqElem->cmd);
	lenPath 	= strlen(pReqElem->path);
	lenParam 	= strlen(pReqElem->param);
	if(	(lenCmd >= S_CLI_MAX_CMD) || (lenPath >= S_APP_MAX_PATH) || (lenParam >= S_CLI_MAX_PARAM)){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg Content Length Error.\n");
		return -1;
	}
		
	/* Path Process, Let's Find out Which Applet is Command Route */
	#if 0
	SYS_TRACE(_gTraceLvl_DevL, TRACELVL_DEBUG, "DevAgt Path:[%s].\n", pReqElem->path);
	#endif
		
	pApplet = NULL;
	bHasSub	= 0;
	subPath[0]='/'; subPath[1]='\0';
	if(lenPath){
		pPath 	= pReqElem->path;
		ret 	= _SAgtDev_Relay_AppletGet(pDevAgt, pPath, lenPath, 
											&pApplet, subPath);
		if(ret == -1){
			return -1;
		}
		else if(ret == 1){
			bHasSub = 1;	
			#if 0
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_DEBUG, "DevAgt SubPath:[%s].\n", subPath);
			#endif
		}
	}
		
	/* Command Process, Prepare the Rsp Msg */
	pRspCmd 	= (_t_cliCmdRsp *)outBuf;
	pCmdHdr 	= &(pRspCmd->cmdHdr);
	CLI_CMDHDR_INIT(pCmdHdr, ipAddr, port);
	
	pRspElem 	= pRspCmd->rspElem;
	switch(pMsgElemReq->type){
		case _CLI_CMD_CONNECT:
			ret = _SAgtDev_CmdConn(pDevAgt, 
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));

			_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			break;
			
		case _CLI_CMD_CD:
			if(bHasSub == 1){
				/* We Just Route It .... */
				_SAGTDEV_CMD_ROUTE(pDevAgt, pApplet, pRouteCmd, pRouteElem, pCmdHdr, pReqElem, ipAddr, port, subPath, lenPath, outBuf, ret);
			}
			else{
				/* Just Return OK */
				ret = _SAgtDev_CmdOk(pDevAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));

				_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			}
			break;
			
		case _CLI_CMD_LS:
			if(bHasSub == 1){
				/* We Just Route It .... */
				_SAGTDEV_CMD_ROUTE(pDevAgt, pApplet, pRouteCmd, pRouteElem, pCmdHdr, pReqElem, ipAddr, port, subPath, lenPath, outBuf, ret);
			}
			else{
				SYS_ENTER_CS(&(pDevAgt->devLock));
				ret = _SAgtDev_CmdLs(pDevAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
				SYS_LEAVE_CS(&(pDevAgt->devLock));
				
				_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			}
			break;
			
		case _CLI_CMD_LCMD:
			if(bHasSub == 1){
				/* We Just Route It .... */
				_SAGTDEV_CMD_ROUTE(pDevAgt, pApplet, pRouteCmd, pRouteElem, pCmdHdr, pReqElem, ipAddr, port, subPath, lenPath, outBuf, ret);
			}
			else{
				SYS_ENTER_CS(&(pDevAgt->devLock));
				ret = _SAgtDev_CmdLCmd(pDevAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
				SYS_LEAVE_CS(&(pDevAgt->devLock));
				
				_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			}
			break;
			
		case _CLI_CMD_EXEC:
			if(bHasSub == 1){
				/* We Just Route It .... */
				_SAGTDEV_CMD_ROUTE(pDevAgt, pApplet, pRouteCmd, pRouteElem, pCmdHdr, pReqElem, ipAddr, port, subPath, lenPath, outBuf, ret);
			}
			else{
				SYS_ENTER_CS(&(pDevAgt->devLock));
				ret = _SAgtDev_CmdExec(pDevAgt,
										(char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr),
										pReqElem->cmd,
										pReqElem->param);
				SYS_LEAVE_CS(&(pDevAgt->devLock));
				
				_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			}
			break;
			
		default:
			SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt RelayMsg Unknown Type:[%d].\n", 
						pMsgElemReq->type);
			return -1;
			break;
	}
		
	return 0;
}

static 	int 	_SAgtDev_RelayStub(void 			* 	pArg, int lArg, 
									unsigned char 	* 	pMsg, 	int msgLen, 
									S_SOCKET_ADDRIN *	pSockAddr)
{
	_t_devAgt		* 	pDevAgt;

	/* Command Request */
	_t_cliCmdReq 	*	pReqCmd;
	_t_cliElemReq	*	pReqElem;

	/* Command Response */
	_t_cliCmdRsp 	* 	pRspCmd;
	_t_cliElemRsp	* 	pRspElem;

	/* Msg Header & Element */
	_t_cliCmdHdr 	*	pCmdHdr;

	/* Command Parse */
	int 				ret;
	unsigned int 		ipAddr;
	unsigned short 		port;

	/* Route / Response Buffer */
	unsigned char 		outBuf[S_CLI_MAX_MSG];

	pDevAgt = (_t_devAgt *)pArg;
	if(!pDevAgt)
		return -1;
	
	ipAddr 	= pSockAddr->sin_addr.s_addr;
	port 	= pSockAddr->sin_port;	

	if(pMsg && (msgLen > 0)){
		/* Check Message */
		pReqCmd = (_t_cliCmdReq *)pMsg;
		pCmdHdr= &(pReqCmd->cmdHdr);

		/* Process the Message */
		pReqElem= (_t_cliElemReq *)(pReqCmd->reqElem);

		if(_SAgtDev_RelayProc(pDevAgt, pReqElem, outBuf, ipAddr, port, pSockAddr) == -1){
			/* Command Error, Prepare the Rsp Msg */
			pRspCmd 	= (_t_cliCmdRsp *)outBuf;
			pCmdHdr 	= &(pRspCmd->cmdHdr);
			CLI_CMDHDR_INIT(pCmdHdr, ipAddr, port);
			
			pRspElem	= pRspCmd->rspElem;
			ret = _SAgtDev_CmdError(pDevAgt, (char *)pRspElem, 
										S_CLI_MAX_MSG - sizeof(_t_cliCmdHdr));
			_SAGTDEV_CMD_RSP(pDevAgt, pCmdHdr, pSockAddr, outBuf, ret);
			return -1;
		}
		return 0;
	}

	return -1;
}

static 	void * 	_SAgtDev_Relay(_t_devAgt* pDevAgt)
{
	int 					ret;
	_t_cbentry 		cbEntry;
	
	/* Check DevAgt Init */
	if(pDevAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return NULL;
	}	

	
	_CBENTRY_INIT(&(cbEntry), _SAgtDev_RelayStub, pDevAgt, 0);

	while(1){
		ret = SockRxSel_Udp(pDevAgt->sockRelay, &cbEntry, _SAGT_DEV_RELAY_TO);
	}
	return NULL;
}

static 	int 	_SAgtDev_CliStub( void 			* 	pArg, int lArg, 
									unsigned char 	* 	pMsg, 	int msgLen, 
									S_SOCKET_ADDRUX *	pSockAddr)
{
	_t_devAgt	* 	pDevAgt;

	/* Command Response */
	_t_cliCmdRsp 	* 	pRspCmd;
	_t_cliElemRsp* 	pRspElem;

	/* Msg Header & Element */
	_t_cliCmdHdr 	*	pCmdHdr;

	int 				ret;
	unsigned int 		ipAddr;
	unsigned short 		port;
	S_SOCKET_ADDRIN 	sockAddr;

	pDevAgt = (_t_devAgt *)pArg;
	if(!pDevAgt)
		return -1;

	ret = -1;
	if(pMsg && (msgLen > 0)){
		pRspCmd = (_t_cliCmdRsp *)pMsg;
		pCmdHdr= &(pRspCmd->cmdHdr);
		pRspElem= pRspCmd->rspElem;
		
		#if 0
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt CliMsg Rsp:[%s].\n", pRspElem->reqRsp);
		#endif
		ipAddr 	= pCmdHdr->ipAddr;
		port 	= pCmdHdr->port;

		sockAddr.sin_family		= AF_INET;
		sockAddr.sin_addr.s_addr= ipAddr;
		sockAddr.sin_port		= port;
		ret = SockTx_Udp(	pDevAgt->sockRelay, pMsg, msgLen, &sockAddr);
	}

	return ret;
}

static 	void * 	_SAgtDev_Cli(_t_devAgt* pDevAgt)
{
	int 					ret;
	_t_cbentry 		cbEntry;
	
	/* Check DevAgt Init */
	if(pDevAgt->bInit == 0){
		SYS_TRACE(_gTraceLvl_DevL, TRACELVL_ERROR, "DevAgt Not Init.\n");
		return NULL;
	}

	_CBENTRY_INIT(&(cbEntry), _SAgtDev_CliStub, pDevAgt, 0);
	while(1){
		ret = SockRxSel_Unix(pDevAgt->sockCli, &cbEntry, _SAGT_DEV_RELAY_TO);
	}
	
	return NULL;
}

/* -----------------------------------------------------------------------
**	Interface Of DevAgent
**
*/
int 	SAgtDev_Init(void)
{
	int 	ret;
	ret = _SAgtDev_Init(&_gAgt_Dev);
	if(ret == -1){
		return -1;
	}

	while(1){
		SYS_SLEEP(5000);
	}
	
	return 0;
}

int 	SAgtDev_AppletAdd(char * appName)
{
	return 	_SAgtDev_AppletAdd(&_gAgt_Dev, appName);
}

int 	SAgtDev_AppletDel(char * appName)
{
	return 	_SAgtDev_AppletDel(&_gAgt_Dev, appName);
}

int 	SAgtDev_Fini(void)
{
	return _SAgtDev_Fini(&_gAgt_Dev);
}


int 	main (int 	argc, char ** argv){

	int 	ret;
	
    daemon(1,1);
	ret = SAgtDev_Init();
	exit (0);
}


